<?php
/**
 * @author jonathan <jo.link.noir@gmail.com>
 * @version 1.0: jo_link_noir
 * @date 04-06-2010
 */
class U1_Army_DAO extends SW_Structure_DAO_Planet
{
	static private $factory = null;


	/**
	 * @return #field
	 */
	static public function getFactory()
	{
		return (self::$factory)
			? self::$factory
			: self::$factory = new self('planet', 'army', null, null, 'ref_user');
	}


	/** @var {idPlanet => {id => U1_Army_Element, ...}, ...}*/
	static private $armies = array();

	/** @var {idPlanet => {group => U1_Army_Element, ...}, ...}*/
	static private $armiesGroup = array();


	/**
	 * @param int $id_structure
	 */
	public function delete($id_structure)
	{
		self::deleteArmy($id_structure);
		parent::delete($id_structure);
	}

	/**
	 * @param array $ids_structure
	 */
	public function deleteElements(array $ids_structure)
	{
		foreach ($ids_structure as $id_s)
			self::deleteArmy($id_s);

		parent::deleteElements($ids_structure);
	}

	/**
	 * @param int $id
	 * @param int $group
	 * @param int $level
	 * @param int $id_planet = null
	 * @param int $duration = null
	 * @param array $price = null
	 * @param int $time_end = null
	 * @return U1_Army_Element
	 */
	protected function newElement($id, $group, $level, $id_planet = null, $duration = null, array $price = null, $time_end = null)
	{
		return self::$armiesGroup[$id_planet][$group] = self::$armies[$id_planet][$id] = new U1_Army_Element($id, $group, $level);
	}

	/**
	 * Supprime les élément enregistré dans la classe
	 */
	static private function deleteArmy($id_struct)
	{
		foreach (self::$armies as $id_p => $armyPlanet)
			if (isset($armyPlanet[$id_structure]))
			{
				unset(
					self::$armiesGroup[$id_p][$armyPlanet[$id_structure]->getGroup()],
					$armyPlanet[$id_structure]
				);
				break;
			}
	}

	/**
	 * Insert une nouvelle liste de construction via un élement
	 * @param SW_Structure_Element $element
	 * @param int $timestamp
	 * @param int $id_planet
	 * @param int $count : nombre pour faire évoluer la structure
	 * @return SW_Structure_List
	 */
	public function createList(SW_Structure_Element $element, $timestamp, $id_planet, $count)
	{
		return parent::createList($element, $timestamp ? $timestamp : $this->getMaxTimestamp($id_planet), $id_planet, $count);
	}

	/**
	 * Arrête la construction d'un élément
	 * @param SW_Structure $structure
	 * @param SW_Structure_List $list
	 * @param int $timestamp
	 */
	public function down(SW_Structure $structure, SW_Structure_List $list, $timestamp)
	{
	}

	/**
	 * Finit la construction d'un élément
	 * @param SW_Structure_Element $element
	 * @param SW_Structure_List $list
	 */
	public function finish(SW_Structure_Element $element, SW_Structure_List $list)
	{
		$element->increse($list->getLevel());
		parent::finish($element, $list);
	}

	/**
	 * @param int $idPlanet
	 * @return int : timestamp maximum
	 */
	public function getMaxTimestamp($idPlanet)
	{
		$method = $this->nameMethodList(__METHOD__);
		if (!isset(self::$queries[$method]))
			$this->prepare($method,
				'SELECT MAX(time_end) FROM '.$this->tableList.' as _l
				JOIN '.$this->tableStructure.' as _s ON _l.'.$this->refStructure.' = _s.id
				WHERE '.$this->refPlanet.'=?'
			);

		self::$queries[$method]->bindParam(1, $id_structure, PDO::PARAM_INT);
		self::$queries[$method]->execute();

		return (int)self::$queries[$method]->fetch(PDO::FETCH_OBJ)->time_end;
	}

	/**
	 * @param int $idPlanet
	 * @param U1_Units|array $army
	 * @attention Ne crée pas les vaisseaux en base s'il n'existe pas
	 */
	public function decrease($idPlanet, $army)
	{
		if (empty($army))
			return;

		$method = $this->nameMethodStructure(__METHOD__);
		if (!isset(self::$queries[$method]))
			$this->prepare($method,
				'UPDATE '.$this->tableStructure.' SET level=level-? WHERE '.$this->refPlanet.'=? AND `group`=?'
			);

		self::_executeQueryUnits(
			self::$queries[$method],
			$idPlanet,
			($army instanceof U1_Units) ? $army->toArray() : $army,
			-1
		);
	}

	/**
	 * @param int $idPlanet
	 * @param U1_Units|array $army
	 * @attention Crée les vaisseaux en base s'il n'existe pas
	 */
	public function increase($idPlanet, $army)
	{
		if (empty($army))
			return;

		$method = $this->nameMethodStructure(__METHOD__);
		if (!isset(self::$queries[$method]))
			$this->prepare($method,
				'INSERT INTO '.$this->tableStructure.'(level, '.$this->refPlanet.', `group`) VALUES (?,?,?)
				ON DUPLICATE KEY UPDATE level=level+VALUES(level), '.$this->refPlanet.'=VALUES('.$this->refPlanet.'), `group`=VALUES(`group`)'
			);

		self::_executeQueryUnits(
			self::$queries[$method],
			$idPlanet,
			($army instanceof U1_Units) ? $army->toArray() : $army,
			1
		);
	}

	/**
	 * @param PDOStatement $state
	 * @param int $idPlanet
	 * @param array $army : {group => quantity, ...}
	 * @param int $signe -1|1
	 */
	static final private function _executeQueryUnits(PDOStatement $state, $idPlanet, array $army, $signe)
	{
		if (isset(self::$armies[$idPlanet]))
		{
			$armyPlanet = &self::$armiesGroup[$idPlanet];
			foreach ($army as $group => $count)
			{
				$state->execute(array($count, $idPlanet, $group));

				if (isset($armyPlanet[$group]))
					$armyPlanet[$group]->increase($signe * $count);
				//ne pas créé de vaisseaux pour la méthode decrease
				else if ($signe === 1)
					$this->newElement((int)$this->pdo->lastInsertId(), $group, $count, $idPlanet);
			}
		}
		else
		{
			foreach ($army as $group => $count)
				$state->execute(
					array($count, $idPlanet, $group)
				);
		}
	}
}